package health_system.health_system.websocket.Test;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.websocket.*;
import jakarta.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
 * WebRTC视频聊天WebSocket服务器
 * 处理用户间的视频通话信令
 */
@Component
@ServerEndpoint("/RemoteAddressForVideoChat1")
public class VideoChatServerBaseWebRTC {
    private static final Logger logger = Logger.getLogger(VideoChatServerBaseWebRTC.class.getName());
    private static final Map<String, Session> sessionMap = new ConcurrentHashMap<>();
    private static final ObjectMapper mapper = new ObjectMapper();
    // 定义消息类型常量
    private static final String TYPE_HANGUP = "hangup";
    private static final String TYPE_CALL_START = "call_start";
    private static final String TYPE_CALL_BACK = "call_back";
    private static final String TYPE_OFFER = "offer";
    private static final String TYPE_ANSWER = "answer";
    private static final String TYPE_ICE = "_ice";
    private static final String SYSTEM_MESSAGE = "系统消息";
    private static final String USER_OFFLINE_MESSAGE = "Sorry，呼叫的用户不在线！";
    private static final String HANGUP_MESSAGE = "对方挂断！";
    static {
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    }
    /**
     * 处理WebSocket连接打开事件
     * @param session WebSocket会话
     */
    @OnOpen
    public void onOpen(Session session) {
        String sessionId = session.getId();
        logger.info("视频聊天服务器连接成功: " + sessionId);
        Optional.ofNullable(extractUsernameFromQueryString(session.getQueryString()))
            .ifPresentOrElse(
                username -> {
                    sessionMap.put(username, session);
                    logger.info("WebSocket opened for user: " + username);
                },
                () -> logger.warning("Invalid username parameter in query string for session: " + sessionId)
            );
    }
    /**
     * 从查询字符串中提取用户名
     * @param queryString 查询字符串
     * @return 用户名，如果未找到则返回null
     */
    public static String extractUsernameFromQueryString(String queryString) {
        if (queryString == null || !queryString.contains("username=")) {
            return null;
        }
        String[] parts = queryString.split("username=");
        if (parts.length < 2) {
            return null;
        }
        String username = parts[1];
        int ampIndex = username.indexOf('&');// 处理可能存在的其他参数
        if (ampIndex != -1) {
            username = username.substring(0, ampIndex);
        }
        return username;
    }
    /**
     * 处理WebSocket连接关闭事件
     * @param session WebSocket会话
     */
    @OnClose
    public void onClose(Session session) {
        Optional.ofNullable(extractUsernameFromQueryString(session.getQueryString()))
            .ifPresent(username -> {
                if (sessionMap.containsKey(username)) {
                    logger.info(username + "--->already_offline");
                    sessionMap.remove(username);
                }
            });
    }
    /**
     * 处理WebSocket错误事件
     * @param session WebSocket会话
     * @param error 错误信息
     */
    @OnError
    public void onError(Session session, Throwable error) {
        String sessionId = session.getId();
        String username = extractUsernameFromQueryString(session.getQueryString());
        logger.log(Level.SEVERE, "WebSocket error for session " + sessionId + 
                  (username != null ? " (user: " + username + ")" : ""), error);
    }
    /**
     * 处理接收到的WebSocket消息
     * @param message 消息内容
     * @param session 发送消息的会话
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        if (message == null || message.isEmpty()) {
            logger.warning("Received empty message from session: " + session.getId());
            return;
        }
        logger.fine("接收到消息: " + message);
        try {
            ChatMessage chatMessage = mapper.readValue(message, ChatMessage.class);
            String type = chatMessage.getType();
            String toUser = chatMessage.getToUser();
            
            if (type == null || toUser == null) {
                logger.warning("Invalid message format: missing required fields");
                return;
            }
            Session toUserSession = sessionMap.get(toUser);
            ChatMessage responseMessage = new ChatMessage();
            responseMessage.setType(type);
            if (toUserSession == null || !toUserSession.isOpen()) {
                responseMessage.setType(TYPE_CALL_BACK);
                responseMessage.setFromUser(SYSTEM_MESSAGE);
                responseMessage.setMsg(USER_OFFLINE_MESSAGE);
                send(session, responseMessage);
                return;
            }
            switch (type) {
                case TYPE_HANGUP:
                    responseMessage.setFromUser(chatMessage.getFromUser());
                    responseMessage.setMsg(HANGUP_MESSAGE);
                    break;
                case TYPE_CALL_START:
                    responseMessage.setFromUser(chatMessage.getFromUser());
                    responseMessage.setMsg("1");
                    break;
                case TYPE_CALL_BACK:
                    responseMessage.setFromUser(toUser);
                    responseMessage.setMsg(chatMessage.getMsg());
                    break;
                case TYPE_OFFER:
                case TYPE_ANSWER:
                    responseMessage.setFromUser(toUser);
                    responseMessage.setSdp(chatMessage.getSdp());
                    break;
                case TYPE_ICE:
                    responseMessage.setFromUser(toUser);
                    responseMessage.setSdpMid(chatMessage.getSdpMid());
                    responseMessage.setSdpMLineIndex(chatMessage.getSdpMLineIndex());
                    responseMessage.setCandidate(chatMessage.getCandidate());
                    break;
                default:
                    logger.warning("Unknown message type: " + type);
                    return;
            }
            send(toUserSession, responseMessage);
        } catch (Exception e) {
            logger.log(Level.SEVERE, "处理消息时出错: " + e.getMessage(), e);
        }
    }
    /**
     * 发送消息到指定会话
     * @param session 目标会话
     * @param message 消息对象
     */
    private void send(Session session, ChatMessage message) {
        try {
            String jsonMessage = mapper.writeValueAsString(message);
            send(session, jsonMessage);
        } catch (JsonProcessingException e) {
            logger.log(Level.SEVERE, "序列化消息失败", e);
        }
    }
    /**
     * 发送文本消息到指定会话
     * @param session 目标会话
     * @param message 消息文本
     */
    private void send(Session session, String message) {
        if (session == null || !session.isOpen()) {
            logger.warning("尝试向无效会话发送消息");
            return;
        }
        try {
            logger.fine("发送消息: " + message);
            synchronized (session) {
                session.getBasicRemote().sendText(message);
            }
        } catch (IOException e) {
            logger.log(Level.SEVERE, "发送消息时出错", e);
        }
    }
    /**
     * 聊天消息模型类
     */
    public static class ChatMessage {
        private String type;
        private String fromUser;
        private String toUser;
        private String msg;
        private String sdp;
        private String sdpMid;
        private Integer sdpMLineIndex;
        private String candidate;
        public String getType() {
            return type;
        }
        public void setType(String type) {
            this.type = type;
        }
        public String getFromUser() {
            return fromUser;
        }
        public void setFromUser(String fromUser) {
            this.fromUser = fromUser;
        }
        public String getToUser() {
            return toUser;
        }
        public void setToUser(String toUser) {
            this.toUser = toUser;
        }
        public String getMsg() {
            return msg;
        }
        public void setMsg(String msg) {
            this.msg = msg;
        }
        public String getSdp() {
            return sdp;
        }
        public void setSdp(String sdp) {
            this.sdp = sdp;
        }
        public String getSdpMid() {
            return sdpMid;
        }
        public void setSdpMid(String sdpMid) {
            this.sdpMid = sdpMid;
        }
        public Integer getSdpMLineIndex() {
            return sdpMLineIndex;
        }
        public void setSdpMLineIndex(Integer sdpMLineIndex) {
            this.sdpMLineIndex = sdpMLineIndex;
        }
        public String getCandidate() {
            return candidate;
        }
        public void setCandidate(String candidate) {
            this.candidate = candidate;
        }
    }
}